﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DungeonGenerator.Tests
{
    using FluentAssertions;

    [TestClass]
    public class DungeonTests
    {
        [TestClass]
        public class GetRoomPoints
        {
            [TestMethod]
            public void NorthMatches()
            {
                var x = 15;
                var y = 12;
                var xlen = 8;
                var ylen = 6;

                var points = DungeonGenerator.Java.Generator.GetRoomPoints(x, y, xlen, ylen, 0).ToArray();
                var manual = new List<PointI>();
                for (int ytemp = y; ytemp > (y - ylen); ytemp--)
                {

                    for (int xtemp = (x - xlen / 2); xtemp < (x + (xlen + 1) / 2); xtemp++)
                    {
                        manual.Add(new PointI() { X = xtemp, Y = ytemp });

                    }
                }
                points.Length.Should().Be(manual.Count);
                var q = from p in points join m in manual on new { p.X, p.Y } equals new { m.X, m.Y } select p;

                q.Count().Should().Be(manual.Count);
                q.Count().Should().Be(points.Count());


            }

            [TestMethod]
            public void NorthMatches2()
            {
                var x = 15;
                var y = 12;
                var xlen = 8;
                var ylen = 8;

                var points = DungeonGenerator.Java.Generator.GetRoomPoints(x, y, xlen, ylen, 0).ToArray();
                var manual = new List<PointI>();
                for (int ytemp = y; ytemp > (y - ylen); ytemp--)
                {

                    for (int xtemp = (x - xlen / 2); xtemp < (x + (xlen + 1) / 2); xtemp++)
                    {
                        manual.Add(new PointI() { X = xtemp, Y = ytemp });

                    }
                }
                points.Length.Should().Be(manual.Count);
                var q = from p in points join m in manual on new { p.X, p.Y } equals new { m.X, m.Y } select p;

                q.Count().Should().Be(manual.Count);
                q.Count().Should().Be(points.Count());


            }

            [TestMethod]
            public void NorthMatchesFor()
            {
                var  direction = Direction.North;
                for (var x = 0; x < 20; x++)
                    for (var y = 0; y < 20; y++)
                        for (var xlen = 1; xlen < 10; xlen++)
                            for (var ylen = 1; ylen < 10; ylen++)
                            {
                                TestNorthMatches(x, y, xlen, ylen, direction);
                            }

            }
						[TestMethod]
						public void NorthMatchesFor20to40()
						{
							var direction = Direction.North;
							for (var x = 20; x < 40; x++)
								for (var y = 20; y < 40; y++)
									for (var xlen = 1; xlen < 10; xlen++)
										for (var ylen = 1; ylen < 10; ylen++)
										{
											TestNorthMatches(x, y, xlen, ylen, direction);
										}

						}

	        static void TestNorthMatches(int x, int y, int xlen, int ylen, Direction direction)
	        {
		        var points = Java.Generator.GetRoomPoints(x, y, xlen, ylen, direction).ToArray();
		        var manual = new List<PointI>();
		        for (int ytemp = y; ytemp > (y - ylen); ytemp--)
		        {
			        for (int xtemp = (x - xlen / 2); xtemp < (x + (xlen + 1) / 2); xtemp++)
			        {
				        manual.Add(new PointI() { X = xtemp, Y = ytemp });
			        }
		        }
		        points.Length.Should().Be(manual.Count);
		        var q = from p in points join m in manual on new { p.X, p.Y } equals new { m.X, m.Y } select p;

		        q.Count().Should().Be(manual.Count);
		        q.Count().Should().Be(points.Count());
	        }

	        [TestMethod]
            public void EastMatchesFor()
            {
                var direction = Direction.East;
                for (var x = 0; x < 20; x++)
                    for (var y = 0; y < 20; y++)
                        for (var xlen = 1; xlen < 10; xlen++)
                            for (var ylen = 1; ylen < 10; ylen++)
                            {
                                TestEastMatches(x, y, xlen, ylen, direction);
                            }

            }

						[TestMethod]
						public void EastMatchesFor20to40()
						{
							var direction = Direction.East;
							for (var x = 20; x < 40; x++)
								for (var y = 20; y < 40; y++)
									for (var xlen = 1; xlen < 10; xlen++)
										for (var ylen = 1; ylen < 10; ylen++)
										{
											TestEastMatches(x, y, xlen, ylen, direction);
										}

						}
	        static void TestEastMatches(int x, int y, int xlen, int ylen, Direction direction)
	        {
		        var points = Java.Generator.GetRoomPoints(x, y, xlen, ylen, direction).ToArray();
		        var manual = new List<PointI>();

		        for (int ytemp = (y - ylen / 2); ytemp < (y + (ylen + 1) / 2); ytemp++)
		        {
			        for (int xtemp = x; xtemp < (x + xlen); xtemp++)
			        {
				        manual.Add(new PointI() { X = xtemp, Y = ytemp });
			        }
		        }
		        points.Length.Should().Be(manual.Count, "points should have the same length as for loop");
		        var q = from p in points join m in manual on new { p.X, p.Y } equals new { m.X, m.Y } select p;

		        q.Count().Should().Be(manual.Count, "join should have same length as for");
		        q.Count().Should().Be(points.Count(), "join should have same length as get");
	        }

	        [TestMethod]
						public void SouthMatchesFor20to40()
						{
							const Direction direction = Direction.South;
							for (var x = 20; x < 40; x++)
								for (var y = 20; y < 40; y++)
									for (var xlen = 1; xlen < 10; xlen++)
										for (var ylen = 1; ylen < 10; ylen++)
										{
											TestSouthMatches(x, y, xlen, ylen, direction);
										}
						}

	        [TestMethod]
            public void SouthMatchesFor()
	        {
		        const Direction direction = Direction.South;
		        for (var x = 0; x < 40; x++)
                    for (var y = 0; y < 40; y++)
                        for (var xlen = 1; xlen < 10; xlen++)
                            for (var ylen = 1; ylen < 10; ylen++)
                            {
                                TestSouthMatches(x, y, xlen, ylen, direction);
                            }
	        }

	        static void TestSouthMatches(int x, int y, int xlen, int ylen, Direction direction)
	        {
		        var points = Java.Generator.GetRoomPoints(x, y, xlen, ylen, direction).ToArray();
		        var manual = new List<PointI>();

		        for (int ytemp = y; ytemp < (y + ylen); ytemp++)
		        {
			        for (int xtemp = (x - xlen / 2); xtemp < (x + (xlen + 1) / 2); xtemp++)
			        {
				        manual.Add(new PointI() { X = xtemp, Y = ytemp });
			        }
		        }
		        points.Length.Should().Be(manual.Count, "points should have the same length as for loop");
		        var q = from p in points join m in manual on new { p.X, p.Y } equals new { m.X, m.Y } select p;

		        q.Count().Should().Be(manual.Count, "join should have same length as for");
		        q.Count().Should().Be(points.Count(), "join should have same length as get");
	        }

	        [TestMethod]
            public void WestMatchesFor()
            {
                var direction = Direction.West;
                for (var x = 0; x < 20; x++)
                    for (var y = 0; y < 20; y++)
                        for (var xlen = 1; xlen < 10; xlen++)
                            for (var ylen = 1; ylen < 10; ylen++)
                            {
                                TestWestMatches(x, y, xlen, ylen, direction);
                            }

            }
					[TestMethod]
					public void WestMatchesFor20to40()
					{
						var direction = Direction.West;
						for (var x = 20; x < 40; x++)
							for (var y = 20; y < 40; y++)
								for (var xlen = 1; xlen < 10; xlen++)
									for (var ylen = 1; ylen < 10; ylen++)
									{
										TestWestMatches(x, y, xlen, ylen, direction);
									}

					}
	        static void TestWestMatches(int x, int y, int xlen, int ylen, Direction direction)
	        {
		        var points = Java.Generator.GetRoomPoints(x, y, xlen, ylen, direction).ToArray();
		        var manual = new List<PointI>();

		        for (int ytemp = (y - ylen / 2); ytemp < (y + (ylen + 1) / 2); ytemp++)
		        {
			        for (int xtemp = x; xtemp > (x - xlen); xtemp--)
			        {
				        {
					        manual.Add(new PointI() { X = xtemp, Y = ytemp });
				        }
			        }
		        }
		        points.Length.Should().Be(manual.Count, "points should have the same length as for loop");
		        var q = from p in points join m in manual on new { p.X, p.Y } equals new { m.X, m.Y } select p;

		        q.Count().Should().Be(manual.Count, "join should have same length as for");
		        q.Count().Should().Be(points.Count(), "join should have same length as get");
	        }
        }
    }
}

